package geppetto.phraseHMM.lexicalWeighting;


import geppetto.cat.alignments.Alignment;
import geppetto.cat.alignments.AlignmentsSet;
import geppetto.lexical.LexicalT;
import geppetto.phraseTable.PhraseTable;
import geppetto.phraseTable.phrase.Phrase;

import java.util.LinkedList;
import java.util.List;



public class WeightedLexicalWeightingCalculator implements
		AbstractLexicalWeightingCalculator {
	LexicalT lexical;
	
	protected AlignmentsSet set;
	protected AlignmentsSet reverseSet;

	public WeightedLexicalWeightingCalculator(AlignmentsSet set, LexicalT lexical) {
		super();
		this.set = set;
		this.reverseSet = set.reverse();
		this.lexical = lexical;
	}

	public double getLexicalWeight(
			int sentenceNumber, int[] sourceSentence, int[] foreingSentence,
			int sourceStartPos, int sourceEndPos, int foreignStartPos,
			int foreignEndPos) {

		return getLexicalWeightInfoForPhrase(set, sentenceNumber, sourceSentence, foreingSentence, sourceStartPos, sourceEndPos, foreignStartPos, foreignEndPos);
	}
	
	public double getReverseLexicalWeight(
			int sentenceNumber, int[] sourceSentence, int[] foreingSentence,
			int sourceStartPos, int sourceEndPos, int foreignStartPos,
			int foreignEndPos) {
		lexical.reverse();
		double ret = getLexicalWeightInfoForPhrase(reverseSet, sentenceNumber, foreingSentence, sourceSentence, foreignStartPos, foreignEndPos, sourceStartPos, sourceEndPos);
		lexical.reverse();
		return ret;
	} 

	public double getLexicalWeightInfoForPhrase(
			AlignmentsSet alignSet, int sentenceNumber,
			int[] sourceSentence, int[] foreingSentence, int sourceStartPos,
			int sourceEndPos, int foreignStartPos, int foreignEndPos) {

		Alignment al = alignSet.get(sentenceNumber);

		Integer[] sourceWords = new Integer[sourceEndPos - sourceStartPos + 1];
		Integer[][] targetWords = new Integer[sourceEndPos - sourceStartPos + 1][];
		Double[][] targetWordsScores = new Double[sourceEndPos - sourceStartPos + 1][];
		Double[] nullScores = new Double[sourceEndPos - sourceStartPos + 1];

		for (int spos = sourceStartPos; spos <= sourceEndPos; spos++) {
			List<Integer> targetArray = new LinkedList<Integer>();
			List<Double> targetScoresArray = new LinkedList<Double>();
			Double nullScore = 1.0;
			for (int fpos = foreignStartPos; fpos <= foreignEndPos; fpos++) {
				if (al._posteriors[spos][fpos]>0) {
					targetArray.add(foreingSentence[fpos]);
					targetScoresArray.add(al._posteriors[spos][fpos]);
				}
				nullScore *= 1.0 - al._posteriors[spos][fpos];
			}
			
			sourceWords[spos - sourceStartPos] = sourceSentence[spos];
			targetWords[spos - sourceStartPos] = targetArray.toArray(new Integer[0]);
			targetWordsScores[spos - sourceStartPos] = targetScoresArray.toArray(new Double[0]);
			nullScores[spos - sourceStartPos] = nullScore;
		}

		double lexicalWeighting = 1;
		for (int index = 0; index < sourceWords.length; index++) {
			Integer sourceWord = sourceWords[index];
			Integer[] targetWordsList = targetWords[index];
			Double nullScore = nullScores[index];
			Double[] targetScores = targetWordsScores[index];
			double localLexicalWeighting = lexical.getProbabilitySF(sourceWord, LexicalT.NULL) * nullScore;
			for(int targetWordIndex = 0; targetWordIndex < targetWordsList.length; targetWordIndex++){
				Integer targetWord = targetWordsList[targetWordIndex];
				Double score = targetScores[targetWordIndex];
				localLexicalWeighting += lexical.getProbabilitySF(
						sourceWord, targetWord) * score
						/ targetWordsList.length;
			}			
			lexicalWeighting *= localLexicalWeighting;			
		}
		return lexicalWeighting;
	}
}
